package iot

import (
	"charging_pile/util/protocol/jiuxing"
	"charging_pile/util/protocol/mq"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"time"

	"github.com/go-netty/go-netty"
	"github.com/zeromicro/go-zero/core/logx"
)

func NewMsgHandler(s *server) netty.ChannelHandler {
	return &msgHandler{
		Server: s,
	}
}

type Attach struct {
	SN      string
	WaitCmd uint8
	from    string
	Timer   *time.Timer
}

type msgHandler struct {
	Server *server
}

func (h *msgHandler) CodecName() string {
	return "jiuxingMsgHandler"
}

func (h *msgHandler) HandleActive(ctx netty.ActiveContext) {
	logx.Infof("Active[%d] %v\n", ctx.Channel().ID(), time.Now())
}

func (h *msgHandler) HandleInactive(ctx netty.InactiveContext, ex netty.Exception) {
	// logx.Infof("Inactive[%d] %v\n", ctx.Channel().ID(), time.Now())
	// atta, _ := ctx.Attachment().(*Attach)
	// if atta != nil {
	// 	h.Server.SnChannelMap.Delete(atta.SN)
	// 	ctx.SetAttachment(nil)
	// }
}

func (h *msgHandler) HandleException(ctx netty.ExceptionContext, ex netty.Exception) {
	logx.Infof("Exception [%d] %v:%+v\n", ctx.Channel().ID(), time.Now(), ex)
}

func (h *msgHandler) HandleEvent(ctx netty.EventContext, event netty.Event) {
	logx.Infof("Event[%d] %v\n", ctx.Channel().ID(), time.Now())
}

func (h *msgHandler) HandleRead(ctx netty.InboundContext, message netty.Message) {
	pkg, ok := message.(*jiuxing.Package)
	if !ok {
		logx.Error("message type error")
		return
	}
	sn := hex.EncodeToString(pkg.Sn)
	if pkg.Cmd == 0x01 {
		ctx.SetAttachment(&Attach{
			SN: sn,
		})
		h.Server.SnChannelMap.Store(sn, ctx.Channel())
	}
	_, ok = h.Server.SnChannelMap.Load(sn)
	if !ok {
		logx.Error("not found channel")
		ctx.Close(nil)
	}
	key := string(pkg.Sn) + string(pkg.Cmd)
	from, ok := h.Server.Cache.Get(key)
	if !ok {
		h.MqPublish(ctx, "", mq.Normal, pkg)
	}
	f, ok := from.(string)
	if !ok {
		return
	}
	h.MqPublish(ctx, f, mq.Normal, pkg)
}

func (h *msgHandler) HandleWrite(ctx netty.OutboundContext, message netty.Message) {
	msg, ok := message.(mq.Msg)
	if !ok {
		return
	}

	switch msg.Cmd {
	case mq.WaitAck:
		jxPkg := &jiuxing.Package{}
		err := json.Unmarshal(msg.Content, jxPkg)
		if err != nil {
			return
		}
		key := msg.Sn + fmt.Sprintf("_%d", jxPkg.Cmd)
		_, ok := h.Server.Cache.Get(key) //value topic && cmd

		if ok {
			h.MqPublish(ctx, msg.From, mq.Busy, &jiuxing.Package{
				Sn:         []uint8(msg.Sn),
				Cmd:        0,
				Encryption: 0,
				PackageLen: 1,
				Check:      0,
			})
			return
		}
		vaule := msg.From + fmt.Sprintf(":%d", jxPkg.Cmd+1)
		h.Server.Cache.Add(key, vaule, time.Second*5)

		param := mq.NeedAck{}
		err = json.Unmarshal(msg.Param, &param)
		if err != nil {
			return
		}
	case mq.Discon:
		ctx.Close(nil)
		return
	}
	m := jiuxing.Package{}
	err := json.Unmarshal(msg.Content, &m)
	if err != nil {
		logx.Error("unmarshal error")
		return
	}

	ctx.Write(m)
}

func (h *msgHandler) MqPublish(ctx netty.HandlerContext, topic string, cmd mq.MqCmd, pkg *jiuxing.Package) {
	pk, _ := json.Marshal(*pkg)
	msg := &mq.Msg{
		From:    h.Server.SvcCtx.LocalTopic,
		Sn:      hex.EncodeToString(pkg.Sn),
		Cmd:     cmd,
		Param:   []byte{},
		Content: pk,
	}
	h.Server.SvcCtx.MQ.HandNettyMsg(msg)
}
